home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / script-fu / script-fu-console.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-19  |  18.0 KB  |  645 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  */
  18.  
  19. #include "config.h"
  20.  
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <sys/types.h>
  25. #if HAVE_DIRENT_H
  26. #include <dirent.h>
  27. #endif
  28. #if HAVE_UNISTD_H
  29. #include <unistd.h>
  30. #endif
  31. #include <sys/stat.h>
  32.  
  33. #include "gdk/gdkkeysyms.h"
  34. #include "gtk/gtk.h"
  35.  
  36. #include "libgimp/gimp.h"
  37. #include "libgimp/gimpui.h"
  38.  
  39. #include "script-fu-intl.h"
  40.  
  41. #include "siod.h"
  42. #include "script-fu-console.h"
  43.  
  44. #include <plug-ins/dbbrowser/dbbrowser_utils.h>
  45.  
  46. #ifdef G_OS_WIN32
  47. #include <fcntl.h>
  48. #include <io.h>
  49. #endif
  50.  
  51. #define TEXT_WIDTH  400
  52. #define TEXT_HEIGHT 400
  53. #define ENTRY_WIDTH 400
  54.  
  55. #define BUFSIZE 256
  56.  
  57. typedef struct
  58. {
  59.   GtkWidget *console;
  60.   GtkWidget *cc;
  61.   GtkAdjustment *vadj;
  62.  
  63.   GdkFont   *font_strong;
  64.   GdkFont   *font_emphasis;
  65.   GdkFont   *font_weak;
  66.   GdkFont   *font;
  67.  
  68.   gint32     input_id;
  69. } ConsoleInterface;
  70.  
  71. /*
  72.  *  Local Functions
  73.  */
  74.  
  75. static void  script_fu_console_interface (void);
  76. static void  script_fu_close_callback    (GtkWidget        *widget,
  77.                       gpointer          data);
  78. static void  script_fu_browse_callback    (GtkWidget        *widget,
  79.                       gpointer          data);
  80. static gboolean script_fu_siod_read      (GIOChannel  *channel,
  81.                       GIOCondition cond,
  82.                       gpointer     data);
  83. static gint  script_fu_cc_is_empty       (void);
  84. static gint  script_fu_cc_key_function   (GtkWidget         *widget,
  85.                       GdkEventKey       *event,
  86.                       gpointer           data);
  87.  
  88. static FILE *script_fu_open_siod_console (void);
  89. static void  script_fu_close_siod_console(void);
  90.  
  91. /*
  92.  *  Local variables
  93.  */
  94.  
  95. static ConsoleInterface cint =
  96. {
  97.   NULL,  /*  console  */
  98.   NULL,  /*  current command  */
  99.   NULL,  /*  vertical adjustment  */
  100.  
  101.   NULL,  /*  strong font  */
  102.   NULL,  /*  emphasis font  */
  103.   NULL,  /*  weak font  */
  104.   NULL,  /*  normal font  */
  105.  
  106.   -1     /*  input id  */
  107. };
  108.  
  109. static char   read_buffer[BUFSIZE];
  110. static GList *history = NULL;
  111. static int    history_len = 0;
  112. static int    history_cur = 0;
  113. static int    history_max = 50;
  114.  
  115. static int   siod_output_pipe[2];
  116. extern long  siod_verbose_level;
  117. extern char  siod_err_msg[];
  118. extern FILE *siod_output;
  119.  
  120.  
  121. #define message(string) printf("(%s): %d ::: %s\n", __PRETTY_FUNCTION__, __LINE__, string)
  122.  
  123. /*
  124.  *  Function definitions
  125.  */
  126.  
  127. void
  128. script_fu_console_run (char     *name,
  129.                int       nparams,
  130.                GimpParam   *params,
  131.                int      *nreturn_vals,
  132.                GimpParam  **return_vals)
  133. {
  134.   static GimpParam values[1];
  135.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  136.   GimpRunModeType run_mode;
  137.  
  138.   run_mode = params[0].data.d_int32;
  139.  
  140.   switch (run_mode)
  141.     {
  142.     case GIMP_RUN_INTERACTIVE:
  143.       /*  Enable SIOD output  */
  144.       script_fu_open_siod_console ();
  145.  
  146.       /*  Run the interface  */
  147.       script_fu_console_interface ();
  148.  
  149.       /*  Clean up  */
  150.       script_fu_close_siod_console ();
  151.       break;
  152.  
  153.     case GIMP_RUN_WITH_LAST_VALS:
  154.     case GIMP_RUN_NONINTERACTIVE:
  155.       status = GIMP_PDB_CALLING_ERROR;
  156.       gimp_message (_("Script-Fu console mode allows only interactive invocation"));
  157.       break;
  158.  
  159.     default:
  160.       break;
  161.     }
  162.  
  163.   *nreturn_vals = 1;
  164.   *return_vals = values;
  165.  
  166.   values[0].type = GIMP_PDB_STATUS;
  167.   values[0].data.d_status = status;
  168. }
  169.  
  170. static void
  171. script_fu_console_interface (void)
  172. {
  173.   GtkWidget *dlg;
  174.   GtkWidget *button;
  175.   GtkWidget *label;
  176.   GtkWidget *vsb;
  177.   GtkWidget *table;
  178.   GtkWidget *hbox;
  179.   GIOChannel *input_channel;
  180.  
  181.   INIT_I18N_UI();
  182.  
  183.   gimp_ui_init ("script-fu", FALSE);
  184.  
  185.   dlg = gtk_dialog_new ();
  186.   gtk_window_set_title (GTK_WINDOW (dlg), _("Script-Fu Console"));
  187.   gimp_help_connect_help_accel (dlg, gimp_standard_help_func, 
  188.                 "filters/script-fu.html");
  189.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  190.               (GtkSignalFunc) script_fu_close_callback,
  191.               NULL);
  192.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  193.               GTK_SIGNAL_FUNC (gtk_widget_destroyed),
  194.               &dlg);
  195.   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->vbox), 2);
  196.   gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dlg)->action_area), 0);
  197.  
  198.   /*  Action area  */
  199.   button = gtk_button_new_with_label (_("Close"));
  200.   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  201.                  (GtkSignalFunc) gtk_widget_destroy,
  202.                  (gpointer)dlg);
  203.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->action_area), button, TRUE, TRUE, 0);
  204.   gtk_widget_show (button);
  205.  
  206.   /*  The info vbox  */
  207.   label = gtk_label_new (_("SIOD Output"));
  208.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  209.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label, FALSE, TRUE, 0);
  210.   gtk_widget_show (label);
  211.  
  212.   /*  The output text widget  */
  213.   cint.vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
  214.   vsb = gtk_vscrollbar_new (cint.vadj);
  215.   cint.console = gtk_text_new (NULL, cint.vadj);
  216.   gtk_text_set_editable (GTK_TEXT (cint.console), FALSE);
  217.   gtk_widget_set_usize (cint.console, TEXT_WIDTH, TEXT_HEIGHT);
  218.  
  219.   table  = gtk_table_new (1, 2, FALSE);
  220.   gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
  221.  
  222.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), table, TRUE, TRUE, 0);
  223.  
  224.   gtk_table_attach (GTK_TABLE (table), vsb, 1, 2, 0, 1,
  225.             0, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  226.   gtk_table_attach (GTK_TABLE (table), cint.console, 0, 1, 0, 1,
  227.             GTK_EXPAND | GTK_SHRINK | GTK_FILL,
  228.             GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
  229.  
  230.   gtk_container_set_border_width (GTK_CONTAINER (table), 2);
  231.  
  232.   cint.font_strong = gdk_font_load ("-*-helvetica-bold-r-normal-*-*-120-*-*-*-*-*-*");
  233.   cint.font_emphasis = gdk_font_load ("-*-helvetica-medium-o-normal-*-*-100-*-*-*-*-*-*");
  234.   cint.font_weak = gdk_font_load ("-*-helvetica-medium-r-normal-*-*-100-*-*-*-*-*-*");
  235.   cint.font = gdk_fontset_load ("-*-*-medium-r-normal-*-*-100-*-*-c-*-iso8859-1,*");
  236.  
  237.   /*  Realize the widget before allowing new text to be inserted  */
  238.   gtk_widget_realize (cint.console);
  239.  
  240.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_strong, NULL, NULL,
  241.            "The GIMP - GNU Image Manipulation Program\n\n", -1);
  242.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_emphasis, NULL, NULL,
  243.            "Copyright (C) 1995-2001\n", -1);
  244.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_emphasis, NULL, NULL,
  245.            "Spencer Kimball, Peter Mattis and the GIMP Development Team\n", -1);
  246.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  247.            "\n", -1);
  248.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  249.            "This program is free software; you can redistribute it and/or modify\n", -1);
  250.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  251.            "it under the terms of the GNU General Public License as published by\n", -1);
  252.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  253.            "the Free Software Foundation; either version 2 of the License, or\n", -1);
  254.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  255.            "(at your option) any later version.\n", -1);
  256.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  257.            "\n", -1);
  258.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  259.            "This program is distributed in the hope that it will be useful,\n", -1);
  260.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  261.            "but WITHOUT ANY WARRANTY; without even the implied warranty of\n", -1);
  262.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  263.            "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n", -1);
  264.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  265.            "See the GNU General Public License for more details.\n", -1);
  266.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  267.            "\n", -1);
  268.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  269.            "You should have received a copy of the GNU General Public License\n", -1);
  270.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  271.            "along with this program; if not, write to the Free Software\n", -1);
  272.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  273.            "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n\n", -1);
  274.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_strong, NULL, NULL,
  275.            "Welcome to SIOD, Scheme In One Defun\n", -1); 
  276.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  277.            "(C) Copyright 1988-1994 Paradigm Associates Inc.\n", -1);
  278.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  279.            "\n\n", -1);
  280.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_strong, NULL, NULL,
  281.            "Script-Fu Console - ", -1);
  282.   gtk_text_insert (GTK_TEXT (cint.console), cint.font_emphasis, NULL, NULL,
  283.            "Interactive Scheme Development\n\n", -1);
  284.  
  285.   gtk_widget_show (vsb);
  286.   gtk_widget_show (cint.console);
  287.   gtk_widget_show (table);
  288.  
  289.   /*  The current command  */
  290.   label = gtk_label_new (_("Current Command"));
  291.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  292.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), label, FALSE, TRUE, 0);
  293.   gtk_widget_show (label);
  294.  
  295.   hbox = gtk_hbox_new ( FALSE, 0 );
  296.   gtk_widget_set_usize (hbox, ENTRY_WIDTH, 0);
  297.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox, FALSE, TRUE, 0);
  298.   gtk_widget_show (hbox);
  299.     
  300.   cint.cc = gtk_entry_new ();
  301.   
  302.   gtk_box_pack_start (GTK_BOX (hbox), cint.cc, 
  303.               TRUE, TRUE, 0);
  304. /*    gtk_widget_set_usize (cint.cc, (ENTRY_WIDTH*5)/6, 0);  */
  305.   GTK_WIDGET_SET_FLAGS (cint.cc, GTK_CAN_DEFAULT);
  306.   gtk_widget_grab_default (cint.cc);
  307.   gtk_signal_connect (GTK_OBJECT (cint.cc), "key_press_event",
  308.               (GtkSignalFunc) script_fu_cc_key_function,
  309.               NULL);
  310.  
  311.   button = gtk_button_new_with_label (_("Browse..."));
  312. /*    gtk_widget_set_usize (button, (ENTRY_WIDTH)/6, 0); */
  313.   gtk_box_pack_start (GTK_BOX (hbox), button, 
  314.               FALSE, TRUE, 0);
  315.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  316.               (GtkSignalFunc) script_fu_browse_callback,
  317.               NULL);
  318.   gtk_widget_show (button);
  319.   gtk_widget_show (cint.cc);
  320.  
  321.   input_channel = g_io_channel_unix_new (siod_output_pipe[0]);
  322.   cint.input_id = g_io_add_watch (input_channel,
  323.                   G_IO_IN,
  324.                   script_fu_siod_read,
  325.                   NULL);
  326.  
  327.   /*  Initialize the history  */
  328.   history = g_list_append (history, NULL);
  329.   history_len = 1;
  330.  
  331.   gtk_widget_show (dlg);
  332.  
  333.   gtk_main ();
  334.  
  335.   g_source_remove (cint.input_id);
  336.   if (dlg)
  337.     gtk_widget_destroy (dlg);
  338.   gdk_flush ();
  339. }
  340.  
  341. static void
  342. script_fu_close_callback (GtkWidget *widget,
  343.               gpointer   data)
  344. {
  345.   gtk_main_quit ();
  346. }
  347.  
  348. void 
  349. apply_callback (gchar           *proc_name,
  350.         gchar           *scheme_proc_name,
  351.         gchar           *proc_blurb,
  352.         gchar           *proc_help,
  353.         gchar           *proc_author,
  354.         gchar           *proc_copyright,
  355.         gchar           *proc_date,
  356.         GimpPDBProcType  proc_type,
  357.         gint             nparams,
  358.         gint             nreturn_vals,
  359.         GimpParamDef    *params,
  360.         GimpParamDef    *return_vals)
  361. {
  362.   gint i;
  363.   GString *text;
  364.  
  365.   if (proc_name == NULL) 
  366.     return;
  367.   
  368.   text = g_string_new ("(");
  369.   text = g_string_append (text, scheme_proc_name);
  370.   for (i=0; i<nparams; i++) 
  371.     {
  372.       text = g_string_append_c (text, ' ');
  373.       text = g_string_append (text, params[i].name);
  374.     }
  375.   text = g_string_append_c (text, ')');
  376.  
  377.   gtk_entry_set_text (GTK_ENTRY (cint.cc), text->str);
  378.   g_string_free (text, TRUE);
  379. }
  380.  
  381. static void
  382. script_fu_browse_callback (GtkWidget *widget,
  383.                gpointer   data)
  384. {
  385.   gtk_quit_add_destroy (1, (GtkObject*) gimp_db_browser (apply_callback));
  386. }
  387.  
  388. static gint
  389. script_fu_console_scroll_end (gpointer data)
  390. {
  391.   /* The Text widget in 1.0.1 doesn't like being scrolled before
  392.    * it is size-allocated, so we wait for it
  393.    */
  394.   if ((cint.console->allocation.width > 1) && 
  395.       (cint.console->allocation.height > 1))
  396.     {
  397.       cint.vadj->value = cint.vadj->upper - cint.vadj->page_size;
  398.       gtk_signal_emit_by_name (GTK_OBJECT (cint.vadj), "changed");
  399.     }
  400.   else
  401.     gtk_idle_add (script_fu_console_scroll_end, NULL);
  402.   
  403.   return FALSE;
  404. }
  405.  
  406. static gboolean
  407. script_fu_siod_read (GIOChannel  *channel,
  408.              GIOCondition cond,
  409.              gpointer     data)
  410. {
  411.   int count;
  412.   static int hack = 0;
  413.   GIOError error;
  414.  
  415.   count = 0;
  416.   error = g_io_channel_read (channel, read_buffer, BUFSIZE - 1, &count);
  417.  
  418.   if (error == G_IO_ERROR_NONE)
  419.     {
  420. #ifndef G_OS_WIN32
  421.       /* Is this needed any longer on Unix? */
  422.       if (!hack) /* this is a stupid hack, but as of 10/27/98
  423.          * the script-fu-console will hang on my system without it.
  424.          * the real cause of this needs to be tracked down.
  425.          * posibly a problem with the text widget, or the
  426.          * signal handlers not getting fully initialized or...
  427.          * no reports of hangs on other platforms, could just be a
  428.          * problem with my system.
  429.          */
  430.       {
  431.     hack = 1;
  432.     return TRUE;
  433.       }
  434. #endif
  435.       read_buffer[count] = '\0';
  436.       gtk_text_freeze (GTK_TEXT (cint.console));
  437.       gtk_text_insert (GTK_TEXT (cint.console), cint.font_weak, NULL, NULL,
  438.                read_buffer, -1);
  439.       gtk_text_thaw (GTK_TEXT (cint.console));
  440.  
  441.       script_fu_console_scroll_end (NULL);
  442.     }
  443.   return TRUE;
  444. }
  445.  
  446. static gint
  447. script_fu_cc_is_empty (void)
  448. {
  449.   char *str;
  450.  
  451.   if ((str = gtk_entry_get_text (GTK_ENTRY (cint.cc))) == NULL)
  452.     return TRUE;
  453.  
  454.   while (*str)
  455.     {
  456.       if (*str != ' ' && *str != '\t' && *str != '\n')
  457.     return FALSE;
  458.  
  459.       str ++;
  460.     }
  461.  
  462.   return TRUE;
  463. }
  464.  
  465. static gint
  466. script_fu_cc_key_function (GtkWidget   *widget,
  467.                GdkEventKey *event,
  468.                gpointer     data)
  469. {
  470.   GList *list;
  471.   int direction = 0;
  472.  
  473.   switch (event->keyval)
  474.     {
  475.     case GDK_Return:
  476.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
  477.  
  478.       if (script_fu_cc_is_empty ())
  479.     return TRUE;
  480.  
  481.       list = g_list_nth (history, (g_list_length (history) - 1));
  482.       if (list->data)
  483.     g_free (list->data);
  484.       list->data = g_strdup (gtk_entry_get_text (GTK_ENTRY (cint.cc)));
  485.  
  486.       gtk_text_freeze (GTK_TEXT (cint.console));
  487.       gtk_text_insert (GTK_TEXT (cint.console), cint.font_strong, NULL, NULL, "=> ", -1);
  488.       gtk_text_insert (GTK_TEXT (cint.console), cint.font, NULL, NULL,
  489.                gtk_entry_get_text (GTK_ENTRY (cint.cc)), -1);
  490.       gtk_text_insert (GTK_TEXT (cint.console), cint.font, NULL, NULL, "\n\n", -1);
  491.       gtk_text_thaw (GTK_TEXT (cint.console));
  492.  
  493.       cint.vadj->value = cint.vadj->upper - cint.vadj->page_size;
  494.       gtk_signal_emit_by_name (GTK_OBJECT (cint.vadj), "changed");
  495.  
  496.       gtk_entry_set_text (GTK_ENTRY (cint.cc), "");
  497.       gdk_flush ();
  498.  
  499.       repl_c_string ((char *) list->data, 0, 0, 1);
  500.       gimp_displays_flush ();
  501.  
  502.       history = g_list_append (history, NULL);
  503.       if (history_len == history_max)
  504.     {
  505.       history = g_list_remove (history, history->data);
  506.       if (history->data)
  507.         g_free (history->data);
  508.     }
  509.       else
  510.     history_len++;
  511.       history_cur = g_list_length (history) - 1;
  512.  
  513.       return TRUE;
  514.       break;
  515.  
  516.     case GDK_KP_Up:
  517.     case GDK_Up:
  518.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
  519.       direction = -1;
  520.       break;
  521.  
  522.     case GDK_KP_Down:
  523.     case GDK_Down:
  524.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
  525.       direction = 1;
  526.       break;
  527.  
  528.     case GDK_P:
  529.     case GDK_p:
  530.       if (event->state & GDK_CONTROL_MASK)
  531.     {
  532.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
  533.       direction = -1;
  534.     }
  535.       break;
  536.  
  537.     case GDK_N:
  538.     case GDK_n:
  539.       if (event->state & GDK_CONTROL_MASK)
  540.     {
  541.       gtk_signal_emit_stop_by_name (GTK_OBJECT (widget), "key_press_event");
  542.       direction = 1;
  543.     }
  544.       break;
  545.  
  546.     default:
  547.       break;
  548.     }
  549.  
  550.   if (direction)
  551.     {
  552.       /*  Make sure we keep track of the current one  */
  553.       if (history_cur == g_list_length (history) - 1)
  554.     {
  555.       list = g_list_nth (history, history_cur);
  556.       if (list->data)
  557.         g_free (list->data);
  558.       list->data = g_strdup (gtk_entry_get_text (GTK_ENTRY (cint.cc)));
  559.     }
  560.  
  561.       history_cur += direction;
  562.       if (history_cur < 0)
  563.     history_cur = 0;
  564.       if (history_cur >= history_len)
  565.     history_cur = history_len - 1;
  566.  
  567.       gtk_entry_set_text (GTK_ENTRY (cint.cc), (char *) (g_list_nth (history, history_cur))->data);
  568.  
  569.       return TRUE;
  570.     }
  571.  
  572.   return FALSE;
  573. }
  574.  
  575.  
  576. static FILE *
  577. script_fu_open_siod_console (void)
  578. {
  579.   if (siod_output == stdout)
  580.     {
  581.       if (pipe (siod_output_pipe))
  582.     {
  583.       gimp_message (_("Unable to open SIOD output pipe"));
  584.     }
  585.       else if ((siod_output = fdopen (siod_output_pipe [1], "w")) == NULL)
  586.     {
  587.       gimp_message (_("Unable to open a stream on the SIOD output pipe"));
  588.       siod_output = stdout;
  589.     }
  590.       else
  591.     {
  592.       siod_verbose_level = 2;
  593.       print_welcome ();
  594.     }
  595.     }
  596.  
  597.   return siod_output;
  598. }
  599.  
  600. static void
  601. script_fu_close_siod_console (void)
  602. {
  603.   if (siod_output != stdout)
  604.     fclose (siod_output);
  605.   close (siod_output_pipe[0]);
  606.   close (siod_output_pipe[1]);
  607. }
  608.  
  609. void
  610. script_fu_eval_run (char     *name,
  611.             int       nparams,
  612.             GimpParam   *params,
  613.             int      *nreturn_vals,
  614.             GimpParam  **return_vals)
  615. {
  616.   static GimpParam values[1];
  617.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  618.   GimpRunModeType run_mode;
  619.  
  620.   run_mode = params[0].data.d_int32;
  621.  
  622.   switch (run_mode)
  623.     {
  624.     case GIMP_RUN_NONINTERACTIVE:
  625.       if (repl_c_string (params[1].data.d_string, 0, 0, 1) != 0)
  626.     status = GIMP_PDB_EXECUTION_ERROR;
  627.       break;
  628.  
  629.     case GIMP_RUN_INTERACTIVE:
  630.     case GIMP_RUN_WITH_LAST_VALS:
  631.       status = GIMP_PDB_CALLING_ERROR;
  632.       gimp_message (_("Script-Fu evaluate mode allows only noninteractive invocation"));
  633.       break;
  634.  
  635.     default:
  636.       break;
  637.     }
  638.  
  639.   *nreturn_vals = 1;
  640.   *return_vals = values;
  641.  
  642.   values[0].type = GIMP_PDB_STATUS;
  643.   values[0].data.d_status = status;
  644. }
  645.